import { provide, inject, ref } from 'vue'
import { TypeFocusState, TypeWidgetItem, TypeBoxItem, TypeKeyDownFn, TypeProvideFocus, TypeWidgetChangeType, TypewidgetChangeFn, TypeInjectFocus, TypeKeys } from "../type";
import { keysOther } from "../path/key"
import { KeyEvents } from "../path/keyMove";
import _ from "lodash"
import { getBoundingClientRect, getUUid } from '../path/until';
class Store extends KeyEvents {
  keys = keysOther
  constructor() {
    super()
  }
  provide(): TypeProvideFocus {
    const keyValue = ref<keyof TypeKeys>()
    const focusId = ref("")
    const switchId = getUUid()
    const _focusState: TypeFocusState = {
      keyValue,
      focusId,
      switchId,
      nextWidget: {
        "widgetId": "",
        "LEFT": "",
        "RIGHT": "",
        "UP": "",
        "DOWN": "",
      },
      widgetList: [],
      boxList: [],
      widgetChangeStore: {},
      keyDownStore: {},
    }
    provide('focus-switch-store', _focusState)
    return {
      state: _focusState,
      changekeyValue: (ev: keyof TypeKeys, keyEv: KeyboardEvent) => {
        for (const key in _focusState.keyDownStore) {
          if (Object.prototype.hasOwnProperty.call(_focusState.keyDownStore, key)) {
            const _fun = _focusState.keyDownStore[key];
            if (typeof _fun === "function") {
              _fun(ev, keyEv)
            }
          }
        }
        return this.changekeyValue(_focusState, ev)
      },
      changeFocus: (ev: string) => this.changeFocus(_focusState, ev),
      listenerWidget: (ev, fn) => this.listenerWidget(ev, fn, _focusState.widgetChangeStore),
      unListenerWidget: (ev) => this.unListenerWidget(ev, _focusState.widgetChangeStore),
    }
  }
  inject(): TypeInjectFocus {
    const _focusState = inject<TypeFocusState>('focus-switch-store', {
      keyValue: ref<keyof TypeKeys>(),
      focusId: ref(""),
      nextWidget: {
        "widgetId": "",
        "LEFT": "",
        "RIGHT": "",
        "UP": "",
        "DOWN": "",
      },
      switchId: "",
      widgetList: [],
      boxList: [],
      widgetChangeStore: {},
      keyDownStore: {},
    })
    return {
      state: _focusState,
      listenerWidget: (ev, fn) => this.listenerWidget(ev, fn, _focusState.widgetChangeStore),
      unListenerWidget: (ev) => this.unListenerWidget(ev, _focusState.widgetChangeStore),
      listenerKeyDown: (ev, fn) => this.listenerKeyDown(ev, fn, _focusState.keyDownStore),
      unListenerKeyDown: (ev) => this.unListenerKeyDown(ev, _focusState.keyDownStore),
      changeFocus: (ev: string) => this.changeFocus(_focusState, ev),
      createWidget: (ev: TypeWidgetItem) => {
        const createInfo = this.createItem(_focusState, "widgetList", ev)
        if (ev.boxId && (typeof _focusState.widgetChangeStore[ev.boxId] === "function")) {
          _focusState.widgetChangeStore[ev.boxId](ev, createInfo.type, createInfo.oldItem as TypeWidgetItem)
        }
        if (typeof _focusState.widgetChangeStore[_focusState.switchId] === "function") {
          _focusState.widgetChangeStore[_focusState.switchId](ev, createInfo.type, createInfo.oldItem as TypeWidgetItem)
        }
        return createInfo
      },
      deleteWidget: (ev: TypeWidgetItem) => {
        this.deleteItem(_focusState, "widgetList", ev)
        if (ev.boxId && (typeof _focusState.widgetChangeStore[ev.boxId] === "function")) {
          _focusState.widgetChangeStore[ev.boxId](ev, "delete")
        }
        return true
      },
      createBox: (ev: TypeBoxItem) => this.createItem(_focusState, "boxList", ev),
      deleteBox: (ev: TypeBoxItem) => this.deleteItem(_focusState, "boxList", ev),
    }
  }

  private listenerWidget(id: string, fn: TypewidgetChangeFn, funs: { [key: string]: TypewidgetChangeFn }) {
    if (typeof fn !== "function") throw new Error("请传入回调函数")
    funs[id] = fn
  }
  private unListenerWidget(id: string, funs: { [key: string]: TypewidgetChangeFn }) {
    delete funs[id]
  }
  private listenerKeyDown(id: string, fn: TypeKeyDownFn, funs: { [key: string]: TypeKeyDownFn }) {
    if (typeof fn !== "function") throw new Error("请传入回调函数")
    funs[id] = fn
  }
  private unListenerKeyDown(id: string, funs: { [key: string]: TypeKeyDownFn }) {
    delete funs[id]
  }
  private changekeyValue(_state: TypeFocusState, ev: keyof TypeKeys) {
    this.watchDom(_state, 10)
    _state.keyValue.value = ev
  }
  private changeFocus(_state: TypeFocusState, ev: string) {
    this.watchDom(_state, 10)
    if (_state.focusId.value === ev) return
    _state.focusId.value = ev
  }
  timer: any = 0;
  private watchDom(state: TypeFocusState, interval = 60) {
    const _boxList = state.boxList
    const _widgetList = state.widgetList
    clearTimeout(this.timer)
    this.timer = 0
    const _this = this
    this.timer = setTimeout(() => {
      for (let i = 0; i < _boxList.length; i++) {
        const _ele = document.getElementById(_boxList[i].uid) || undefined
        state.boxList[i].ele = _ele
        state.boxList[i].rect = getBoundingClientRect(_ele)
      }
      let widgetItem: TypeWidgetItem | undefined = undefined
      for (let i = 0; i < _widgetList.length; i++) {
        const _ele = document.getElementById(_widgetList[i].uid) || undefined
        state.widgetList[i].ele = _ele
        state.widgetList[i].rect = getBoundingClientRect(_ele)
        if (state.focusId.value && state.focusId.value === _widgetList[i].uid) {
          widgetItem = _widgetList[i]
        }
      }
      if (widgetItem) {
        state.nextWidget = {
          "widgetId": widgetItem.uid,
          "LEFT": _this.findNextFocus(state, "LEFT", widgetItem),
          "RIGHT": _this.findNextFocus(state, "RIGHT", widgetItem),
          "UP": _this.findNextFocus(state, "UP", widgetItem),
          "DOWN": _this.findNextFocus(state, "DOWN", widgetItem),
        }
      }
    }, interval);
  }
  private createItem(_state: TypeFocusState, typeKey: keyof TypeFocusState, item: { uid: string }): { type: TypeWidgetChangeType, oldItem?: { uid: string } } {
    const returnObj: { type: TypeWidgetChangeType, oldItem?: { uid: string } } = { type: "none" };
    const _val = _state[typeKey]
    if (!(_val instanceof Array)) return returnObj
    const _list = [..._val];
    const _index = _list.findIndex(function (v) { return v.uid === item.uid });
    if (_index > -1) {
      returnObj.oldItem = _.cloneDeep(_list[_index])
      _list[_index] = {
        ...returnObj.oldItem,
        ...(item as any)
      }
      returnObj.type = "change"
    } else {
      returnObj.type = "create"
      _list.push(item as any);
    }
    (_state[typeKey] as any) = _list as any
    this.watchDom(_state)
    return returnObj
  }
  private deleteItem(_state: TypeFocusState, typeKey: keyof TypeFocusState, item: { uid: string }) {
    const _val = _state[typeKey]
    if (_val instanceof Array) {
      const _list = [..._val];
      const _index = _list.findIndex(function (v) { return v.uid === item.uid });
      if (_index > -1) {
        if (item.uid === _state.focusId.value) {
          const _nextId = _list[_index + 1]?.uid || _list[_index - 1]?.uid
          _nextId && this.changeFocus(_state, _nextId)
        }
        _list.splice(_index, 1);
        (_state[typeKey] as any) = _list as any
      }
    }
    this.watchDom(_state)
  }
}
export default new Store()